﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HelloWorld.RobotFights
{
    public class GameLogic
    {
        private int _fieldHeight;
        private int _fieldWidth;
        private int _delay = 100;
        private List<Robot> _playingRobots = new List<Robot>();
        private List<Block> _blocks = new List<Block>();
        private Random _random = new Random();
        private int _targetX;
        private int _targetY;

        private InputHandler _userInputHandler;

        /// <summary>
        /// Method for detecting cell status
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="robot"></param>
        /// <returns>
        /// Returns  0 if cell is free
        /// 1 if cell is game border or block
        /// 2 if cell is another robot
        /// 
        /// </returns>
        public int IsPositionFree(int x, int y,Robot robot = null)
        {
            foreach (Robot r in _playingRobots)
            {
                if (r.x == x && r.y == y)
                {
                    if (r == robot)
                        continue;

                    return 2;
                }
            }

            foreach (Block r in _blocks)
            {
                if (r.X == x && r.Y == y)
                {
                    return 1;
                }
            }

            return (x >= 0 && y >= 0 && x < _fieldWidth & y < _fieldHeight) ? 0 : 1;
        }

        public GameLogic(InputHandler inputHandler)
        {
            _userInputHandler = inputHandler;
        }


        private void PrintTarget()
        {
            Console.SetCursorPosition(_targetX, _targetY);
            Console.Write("@");
        }

        public void StartGame(int fieldHeight, int fieldWidth, IEnumerable <Robot> robots,int? blocksCount = null)
        {
            if (fieldHeight <= 5)
                throw new ArgumentOutOfRangeException("fieldHeight must be greater than 4");

            if (fieldWidth <= 5)
                throw new ArgumentOutOfRangeException("fieldWidth must be greater than 4");

            if (robots == null && robots.Count() == 0)
                throw new ArgumentException("At least one robot must be passed");

            _userInputHandler.SpeedUp += OnSpeedUpRequest;
            _userInputHandler.SpeedDown += OnSpeedDownRequest; 

         


            _fieldHeight = fieldHeight;
            _fieldWidth = fieldWidth;

            Console.SetWindowSize(fieldWidth, fieldHeight);

            foreach (Robot r in robots)
                IntRobotPosition(r);

            if (blocksCount.HasValue)
            {
                int blockAmount = blocksCount.Value;
                while(blockAmount-- > 0)
                {
                    InitBlockPosition();
                }
            }

            InitTargetPosition();

            PrintTarget();

            while (IsWinnerFound() == null)
            {
                foreach (Robot r in this._playingRobots)
                {
                    int currentRobotX = r.x;
                    int currentRobotY = r.y;

                    try
                    {
                        _userInputHandler.QueryKeyBoard();

                        r.DoStep(IsPositionFree);
                        if (IsPositionFree(r.x,r.y,r) != 0 ||  Math.Abs(r.x - currentRobotX) > 1 || Math.Abs(r.y - currentRobotY) > 1)
                            r.SetPosition(currentRobotX, currentRobotY);
                    }
                    catch
                    {
                        r.SetPosition(currentRobotX, currentRobotY);
                    }
                    r.Print();

                    if (_delay > 0)
                        Thread.Sleep(_delay);
                }
                foreach (Block b in this._blocks)
                {
                    b.Print();
                }
            }
        }

        private void OnSpeedDownRequest(object sender, EventArgs e)
        {
            _delay += 10;
            Debug.WriteLine("Delay has been increased to {0}", _delay);
        }

        private void OnSpeedUpRequest(object sender, EventArgs e)
        {
            if (_delay >= 10)
                _delay -= 10;

            Debug.WriteLine("Delay has been decreased to {0}", _delay);
        }

        private void InitBlockPosition()
        {
            int x, y = 0;
            do
            {
                x = _random.Next(0, this._fieldWidth - 1);
                y = _random.Next(0, this._fieldHeight - 1);
            } while (IsPositionFree(x, y) != 0);

            _blocks.Add(new Block(x, y));
        }

        private void IntRobotPosition(Robot r)
        {
            int x,y = 0;
            do
            {
                x = _random.Next(0, this._fieldWidth-1);
                y = _random.Next(0, this._fieldHeight-1);
            } while(IsPositionFree(x,y)!=0);
            
            r.SetPosition(x, y);
            _playingRobots.Add(r);
        }

        private void InitTargetPosition()
        {
            int x;
            int y;
            do 
            {
                x = _random.Next(0, this._fieldWidth-1);
                y = _random.Next(0, this._fieldHeight-1);
            } while(IsPositionFree(x,y)!=0);
            _targetX = x;
            _targetY = y;
        }

        private Robot IsWinnerFound()
        { 
            foreach(Robot r in this._playingRobots)
            {
                if (r.x==this._targetX && r.y == this._targetY)
                    return r;
            }
            return null;
        }
    }
}
